﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


//////////////////////////////////////////////////////
//////WILLL BEEEE USED IN THE FUTURE//////////////////
//////////////////////////////////////////////////////

/// <summary>
/// Component that handles 2D animation based on multiple frames 
/// held within a single texture.
/// </summary>
internal class AnimationComponent : DrawableGameComponent
{
    /// <summary>
    /// Screen position of the animation top-right corner.
    /// </summary>
    public Vector2 Position;

    /// <summary>
    /// Whether or not the animation will repeat when completed.
    /// </summary>
    public bool Loop;

    /// <summary>
    /// Default delay between animation frames (in milliseconds).
    /// </summary>
    public int FrameDelay;

    /// <summary>
    /// Renders the current animation frame.
    /// </summary>
    SpriteBatch spriteBatch;

    /// <summary>
    /// Texture cintaining the animation frames.
    /// </summary>
    Texture2D texture;

    /// <summary>
    /// Path to the texture to animate.
    /// </summary>
    string texturePath;

    /// <summary>
    /// Width of a single frame.
    /// </summary>
    int width;

    /// <summary>
    /// Height of a single frame.
    /// </summary>
    int height;

    /// <summary>
    /// Table of the delay between each animation frame
    /// (in milliseconds).
    /// </summary>
    int[][] frameInfo;

    /// <summary>
    /// Current frame column index.
    /// </summary>
    int frameX;

    /// <summary>
    /// Current frame row index.
    /// </summary>
    int frameY;

    /// <summary>
    /// Last game time when the animation frame switched.
    /// </summary>
    TimeSpan lastGameTime;

    /// <summary>
    /// Whether or not the animation is running.
    /// </summary>
    bool paused;

    /// <summary>
    /// Create a new <see cref="AnimationComponent" /> based on the given texture.
    /// </summary>
    /// <param name="game">Containing game.</param>
    /// <param name="textureName">Name of the texture to animate.</param>
    /// <param name="frameHeight">Height of a single animation frame.</param>
    /// <param name="frameWidth">Width of a single animation frame.</param>
    public AnimationComponent(Game game, string textureName, int frameWidth,
                              int frameHeight)
        : base(game)
    {
        paused = true;
        FrameDelay = 66;

        // save the texture information
        width = frameWidth;
        height = frameHeight;
        texturePath = textureName;
    }

    /// <summary>
    /// Play the animation.
    /// </summary>
    /// <remarks>Resets the animation to the first frame if it was
    /// not already playing.</remarks>
    public void Play()
    {
        if (paused)
        {
            frameX = frameY = 0;
        }
        paused = false;
    }

    /// <summary>
    /// Pause the animation at the current frame.
    /// </summary>
    public void Pause()
    {
        paused = true;
    }

    /// <summary>
    /// Stop the animation.
    /// </summary>
    public void Stop()
    {
        paused = true;
    }

    /// <summary>
    /// Load the animation content.
    /// </summary>
    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);

        // load the animation texture sheet
        texture = Game.Content.Load<Texture2D>(texturePath);

        // determine the number of rows and columns in the animation
        // based on the dimensions of a single frame
        int rows = texture.Height / height;
        int columns = texture.Width / width;

        // populate the animation frame time (in milliseconds) for each
        // frame of the rectangular texture. These are initially all the
        // same but using arrays supports the ability to tweak the delay
        // between individual frames
        frameInfo = new int[rows][];
        for (int y = 0; y < rows; y++)
        {
            frameInfo[y] = new int[columns];
            for (int x = 0; x < columns; x++)
            {
                frameInfo[y][x] = FrameDelay;
            }
        }
    }

    /// <summary>
    /// Handle updating the animation.
    /// </summary>
    /// <param name="gameTime">Current game time.</param>
    public override void Update(GameTime gameTime)
    {
        if (!paused)
        {
            int delay = frameInfo[frameY][frameX];
            if ((gameTime.TotalGameTime - lastGameTime).TotalMilliseconds > delay)
            {
                // if at the end of a row the animation must move to the next one,
                // otherwise it will have moved to the next column
                if (++frameX >= frameInfo[frameY].Length)
                {
                    // at the end of the last row in a non-looping animation
                    if (frameY + 1 == frameInfo.Length && !Loop)
                    {
                        paused = true;
                        frameX--;
                    }

                    // the animation loops or there are more rows available.
                    // Go to the first column in the next row
                    else
                    {
                        frameY = ++frameY % frameInfo.Length;
                        frameX = 0;
                    }
                }

                // record the last time that the current frame switched
                lastGameTime = gameTime.TotalGameTime;
            }
        }
    }

    /// <summary>
    /// Render the current animation frame.
    /// </summary>
    /// <param name="gameTime">Current game time.</param>
    public override void Draw(GameTime gameTime)
    {
        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred,
                          SaveStateMode.SaveState);
        spriteBatch.Draw(texture, Position,
                         new Rectangle(frameX * width, frameY * height, width, height),
                         Color.White);
        spriteBatch.End();
    }
}